package Test;

import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

import Class.User;
/**
 * 用户管理系统主程序类
 * 包含用户登录、注册、密码找回、查询所有用户等功能
 */
public class App {
    public static void main(String[] args) {
        // 创建Scanner对象用于接收用户输入
        Scanner scanner = new Scanner(System.in);
        // 创建ArrayList集合存储所有用户对象
        ArrayList<User> list = new ArrayList<User>();
        // 初始化两个测试用户并添加到集合中
        User u1 = new User("tcs123", "123456", "131126200401255414", "15614827006");
        User u2 = new User("tmh124", "123456", "131126200901255426", "17814827006");
        list.add(u1);
        list.add(u2);
        // 无限循环展示主界面，直到用户选择退出
        while (true) {
            // 打印主界面菜单
            Desktop();
            System.out.print("请输入键位：");
            int key = scanner.nextInt();// 获取用户选择的功能编号
            switch (key) {
                case 1 -> login(list); // 1：用户登录
                case 2 -> register(list); // 2：注册用户
                case 3 -> forgetPassword(list);// 3：忘记密码
                case 4 -> getAllUser(list);// 4：查看所有用户
                case 0 -> {// 0：退出系统
                    System.out.println("已退出系统");
                    System.exit(0);// 终止程序运行
                }
                default -> System.out.println("键位输入错误！！！");// 输入无效键位
            }
        }

    }
    /**
     * 打印系统主界面菜单
     * 展示所有可用功能及对应键位
     */
    public static void Desktop() {
        System.out.println("==========用户界面============");
        System.out.println("==   1        用户登入      ==");
        System.out.println("==   2        注册用户      ==");
        System.out.println("==   3        忘记密码      ==");
        System.out.println("==   4        所有用户      ==");
        System.out.println("==   0        退出系统      ==");
        System.out.println("============================");
    }
    /**
     * 用户注册功能
     * 接收用户输入的信息，验证格式并添加到用户集合中
     * @param list 存储所有用户的集合
     */
    public static void register(ArrayList<User> list) {
        Scanner scanner = new Scanner(System.in);
        User user = new User();// 创建新用户对象存储注册信息
        //验证用户名（循环直到输入符合要求）
        while (true) {
            System.out.print("请输入用户名：");
            String username = scanner.next();
            // 用户名长度需在3-15之间
            if (username.length() >= 3 && username.length() <= 15) {
                // 验证用户名格式（必须包含字母和数字）
                if (compareUsername(username)) {
                    // 检查用户名是否已存在
                    if (!contain(list, username)) {
                        user.setUsername(username);// 符合要求则设置用户名
                        break;// 跳出循环，结束用户名输入
                    } else System.out.println("用户名已存在，无法注册");
                } else {
                    System.out.println("用户名格式问题");
                }
            } else {
                System.out.println("用户名长度问题");
            }
        }
        //验证密码（循环直到两次输入一致）
        while (true) {
            System.out.print("请输入密码：");
            String password = scanner.next();
            System.out.print("请再次输入密码：");
            String newPassword = scanner.next();
            if (password.equals(newPassword)) {// 两次密码需一致
                user.setPassword(password);// 设置密码
                break;// 跳出循环，结束密码输入
            } else System.out.println("密码不一致");
        }
        //验证身份证（循环直到输入符合要求）
        while (true) {
            System.out.print("请输入身份证：");
            String personId = scanner.next();
            if (comparePersonId(personId)) {// 验证身份证号格式
                user.setPersonalId(personId);// 设置身份证号
                break;// 跳出循环，结束身份证号输入
            } else {
                System.out.println("身份证号格式错误");
            }
        }
        //验证手机号（循环直到输入符合要求）
        while (true) {
            System.out.print("请输入手机号：");
            String phoneNumber = scanner.next();
            if (comparePhoneNumber(phoneNumber)) {// 验证手机号格式
                user.setPhoneNumber(phoneNumber);// 设置手机号
                break;// 跳出循环，结束手机号输入
            } else {
                System.out.println("手机号格式错误");
            }
        }
        // 将注册成功的用户添加到集合
        list.add(user);
        // 打印注册成功的用户信息
        System.out.println("姓名：" + user.getUsername() + " " +
                "密码：" + user.getPassword() + " " +
                "身份证号：" + user.getPersonalId() + " " +
                "手机号：" + user.getPhoneNumber());
        System.out.println("注册成功");
    }
    /**
     * 用户登录功能
     * 验证用户名、密码及验证码，支持3次错误尝试
     * @param list 存储所有用户的集合
     */
    public static void login(ArrayList<User> list) {
        Scanner scanner = new Scanner(System.in);
        // 最多允许3次登录尝试
        for (int i = 1; i <= 3; i++) {
            System.out.print("请输入用户名：");
            String username = scanner.next();
            System.out.print("请输入密码：");
            String password = scanner.next();
            // 检查用户名是否已注册
            if (!contain(list, username)) {
                System.out.println("用户名未注册，请先注册");
                return;// 直接返回主界面
            }
            // 验证验证码（循环直到输入正确）
            while (true) {
                String code = getCode();// 生成验证码
                System.out.println("验证码：" + code);
                System.out.print("请输入验证码：");
                String inputCode = scanner.next();
                // 忽略大小写验证验证码
                if (code.equalsIgnoreCase(inputCode)) {
                    break;// 验证码正确，跳出循环
                } else {
                    System.out.println("验证码输入错误");
                }
            }
            // 创建临时用户对象用于验证
            User user = new User(username, password, "", "");
            // 验证用户名和密码是否匹配
            if (compareUser(list, user)) {
                System.out.println("登入成功");
                Test.StudentInfoSystem();//直接进入学生信息管理系统
                break;
            } else {
                // 提示剩余尝试次数，3次错误则锁定账号
                if (i == 3) System.out.println("用户名：" + username + "已被Tcs集团锁定");
                else System.out.println("用户名或密码错误，还有" + (3 - i) + "次机会");
            }
        }
    }
    /**
     * 忘记密码功能
     * 通过用户名、身份证号和手机号验证后修改密码
     * @param list 存储所有用户的集合
     */
    public static void forgetPassword(ArrayList<User> list) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名：");
        String username = scanner.next();
        // 检查用户名是否存在
        if (!contain(list, username)) {
            System.out.println("用户名：" + username + "不存在");
            return;// 直接返回主界面
        }
        System.out.print("请输入身份证号：");
        String personId = scanner.next();
        // 验证用户名和身份证号是否匹配，返回匹配的用户索引
        int index = checkUser(list, username, personId);
        if (index < 0) {// 索引为-1表示不匹配
            System.out.println("用户名与身份证号不符");
            return;// 直接返回主界面
        }
        // 验证手机号并修改密码
        while (true) {
            System.out.print("请输入手机号：");
            String phoneNumber = scanner.next();
            // 验证手机号是否与该用户匹配
            if (list.get(index).getPhoneNumber().equals(phoneNumber)) {
                System.out.print("请输入新的密码：");
                String newPassword = scanner.next();
                // 修改密码并保存
                list.get(index).setPassword(newPassword);
                System.out.println("密码修改成功");
                break;// 修改成功，跳出循环
            } else {
                System.out.println("账号信息不匹配，修改失败");
            }
        }

    }
    /**
     * 验证用户名和身份证号是否匹配
     * @param list 存储所有用户的集合
     * @param username 待验证的用户名
     * @param personId 待验证的身份证号
     * @return 匹配的用户在集合中的索引，不匹配则返回-1
     */
    public static int checkUser(ArrayList<User> list, String username, String personId) {
        for (int i = 0; i < list.size(); i++) {
            User user = list.get(i);
            // 同时匹配用户名和身份证号
            if (user.getUsername().equals(username) && user.getPersonalId().equals(personId)) return i; // 返回匹配的索引
        }
        return -1;// 无匹配用户
    }
    /**
     * 验证用户名和密码是否匹配
     * @param list 存储所有用户的集合
     * @param user 包含待验证用户名和密码的用户对象
     * @return 匹配返回true，否则返回false
     */
    public static boolean compareUser(ArrayList<User> list, User user) {
        for (int i = 0; i < list.size(); i++) {
            // 同时匹配用户名和密码
            if (list.get(i).getUsername().equals(user.getUsername()) && list.get(i).getPassword().equals(user.getPassword()))
                return true;// 匹配成功
        }
        return false;// 匹配失败
    }
    /**
     * 验证用户名格式
     * 要求：必须包含至少1个字母（大小写均可）和1个数字
     * @param username 待验证的用户名
     * @return 格式正确返回true，否则返回false
     */
    public static boolean compareUsername(String username) {
        //测试用户名是否包含大小写字母和数字
        for (int i = 0; i < username.length(); i++) {
            char c = username.charAt(i);
            // 若存在非字母非数字字符，直接返回false
            if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) return false;
        }
        // 统计字母和数字的数量
        int letterCount = 0;
        int numberCount = 0;
        for (int i = 0; i < username.length(); i++) {
            char c = username.charAt(i);
            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) letterCount++;// 字母计数+1
            if (c >= '0' && c <= '9') numberCount++;// 数字计数+1
        }
        // 必须同时包含字母和数字
        return letterCount > 0 && numberCount > 0;
    }
    /**
     * 验证身份证号格式
     * 要求：18位字符，前17位为数字，最后一位可为数字或X/x
     * @param personId 待验证的身份证号
     * @return 格式正确返回true，否则返回false
     */
    public static boolean comparePersonId(String personId) {
        // 身份证号必须为18位
        if (personId.length() != 18) return false;
        // 身份证号不能以0开头
        if (personId.startsWith("0")) return false;
        // 前17位必须为数字
        for (int i = 0; i < personId.length() - 1; i++) {
            char c = personId.charAt(i);
            if (!(c >= '0' && c <= '9')) return false;
        }
        // 最后一位可以是数字或X/x
        char c = personId.charAt(personId.length() - 1);
        if ((c >= '0' && c <= '9') || c == 'x' || c == 'X') return true;
        else return false;
    }
    /**
     * 验证手机号格式
     * 要求：11位数字，不能以0开头
     * @param phoneNumber 待验证的手机号
     * @return 格式正确返回true，否则返回false
     */
    public static boolean comparePhoneNumber(String phoneNumber) {
        // 手机号必须为11位
        if (phoneNumber.length() != 11) return false;
        // 手机号不能以0开头
        if (phoneNumber.startsWith("0")) return false;
        // 所有字符必须为数字
        for (int i = 0; i < phoneNumber.length(); i++) {
            char c = phoneNumber.charAt(i);
            if (!(c >= '0' && c <= '9')) return false;
        }
        return true;
    }
    /**
     * 打印所有用户的信息
     * @param list 存储所有用户的集合
     */
    public static void getAllUser(ArrayList<User> list) {
        // 遍历集合，打印每个用户的详细信息
        for (int i = 0; i < list.size(); i++) {
            System.out.println("姓名：" + list.get(i).getUsername() + " " +
                    "密码：" + list.get(i).getPassword() + " " +
                    "身份证号：" + list.get(i).getPersonalId() + " " +
                    "手机号：" + list.get(i).getPhoneNumber());
        }
    }
    /**
     * 检查用户名是否已存在于集合中
     * @param list 存储所有用户的集合
     * @param username 待检查的用户名
     * @return 存在返回true，否则返回false
     */
    public static boolean contain(ArrayList<User> list, String username) {
        for (int i = 0; i < list.size(); i++) {
            // 遍历集合比对用户名
            if (list.get(i).getUsername().equals(username)) return true;// 用户名已存在
        }
        return false;// 用户名不存在
    }

    /**
     * 生成随机验证码
     * 格式：4个字母（大小写随机）+1个数字，字符位置随机交换
     * @return 生成的验证码字符串
     */
    public static String getCode() {
        Random random = new Random();
        // 用于拼接验证码字符
        StringBuilder sb = new StringBuilder();
        char[] arr;// 存储验证码字符的数组（用于交换位置）
        char temp;// 交换字符时的临时变量
        int numberIndex;// 数字在验证码中的位置
        // 创建存储所有字母（大小写）的集合
        ArrayList<Character> list = new ArrayList<>();
        for (int i = 0; i < 26; i++) {
            list.add((char) ('a' + i));// 添加小写字母
            list.add((char) ('A' + i));// 添加大写字母
        }
        // 随机选择4个字母添加到验证码
        for (int i = 0; i < 4; i++) {
            int randomIndex = random.nextInt(list.size());// 随机索引
            sb.append(list.get(randomIndex));// 拼接字母
        }
        // 添加1个随机数字（0-9）
        sb.append(random.nextInt(10));
        // 随机交换数字与某个字母的位置（让数字位置不固定）
        numberIndex = random.nextInt(4);// 生成0-3的随机索引（字母位置）
        arr = sb.toString().toCharArray();// 转换为字符数组

        // 交换数字（最后一位）与随机字母的位置
        temp = arr[numberIndex];
        arr[numberIndex] = arr[arr.length - 1];
        arr[arr.length - 1] = temp;

        // 将字符数组转换为字符串并返回
        return new String(arr);
    }
}
